#!/usr/bin/wish


### Read file for debug
  set ifn "test.v"
  set fcont ""
  set IFH [open $ifn "r"]
  while { ![eof $IFH] } {
    set line [gets $IFH]
    lappend fcont $line
  }
  close $IFH
###

set mtagn 0

proc redraw_cnv {} {
  .cnv addtag ttt all
  .cnv delete ttt
  set first_line [get_first_line_num]
  set last_line  [expr $first_line + [get_text_height] ]
  for {set i $first_line} { $i < $last_line } { incr i } {
    set ind "$i.0"
    if { [ check_mtag $ind ] } { 
      set n [ get_mtag_n $ind ]
      set char_box [.txt_ bbox $ind]
      #puts $char_box
      set x1 2
      set y1 [ expr [lindex $char_box 1] + [lindex $char_box 3 ] - 11 ]
      set x2 [ expr $x1+8 ]
      set y2 [ expr $y1+8 ]
      .cnv addtag mbox$n withtag [.cnv create rectangle $x1 $y1 $x2 $y2 -width 1 -outline black -fill SkyBlue2]
      .cnv addtag mbox$n withtag [.cnv create line [expr $x1 + 2] [expr $y1 + 4] [expr $x2 - 1] [expr $y2 - 4] -width 1]
      if { [check_reduced $ind] } {
        .cnv addtag mbox$n withtag [.cnv create line [expr $x1 + 4] [expr $y1 + 2] [expr $x2 - 4] [expr $y2 - 1] -width 1]
      }
      .cnv bind mbox$n <1> "mbox_pressed $n"
    }
    if { [ check_reduced_ $ind ] } { incr last_line }
  };#for i
}

proc mbox_pressed { n } {
  if { [check_reduced mtag$n.first] } {
    .txt_ tag configure mtag${n}_ -elide 0
    .txt_ tag remove reduced mtag$n.first mtag$n.last
    .txt_ tag remove reduced_ mtag${n}_.first mtag${n}_.last
  } else {
    #puts "Pressed mbox #$n"
    .txt_ tag configure mtag${n}_ -elide 1
    .txt_ tag add reduced mtag$n.first mtag$n.last
    .txt_ tag add reduced_ mtag${n}_.first mtag${n}_.last
  }
  redraw_cnv
  update_lln
}

proc check_reduced { ind } {
  set tags [ .txt_ tag names $ind ]
  foreach tag $tags {
    if { $tag == "reduced" } {return 1}
  }
  return 0
}

proc check_reduced_ { ind } {
  set tags [ .txt_ tag names $ind ]
  foreach tag $tags {
    if { $tag == "reduced_" } {return 1}
  }
  return 0
}

proc check_mtag { ind } {
  set tags [ .txt_ tag names $ind ]
  foreach tag $tags {
    if { [regexp {^mtag\d+$} $tag ] } {return 1}
  }
  return 0
}

proc check_mtag_ { ind } {
  set tags [ .txt_ tag names $ind ]
  foreach tag $tags {
    if { [regexp {^mtag\d_+$} $tag ] } {return 1}
  }
  return 0
}


proc get_mtag_n { ind } {
  set tags [ .txt_ tag names $ind ]
  foreach tag $tags {
    if { [regexp {^mtag(\d+)} $tag m m1] } {return $m1}
  }
  return -1
}

proc update_lln {} {
  global lnstr
  set lnstr ""
  
  set first_line [get_first_line_num]
  #set last_line [get_last_line_num] 
  set last_line [expr $first_line + [get_text_height] ]
  set j $first_line
  for {set i $first_line} { $i < $last_line } { incr i } {
    set ind "$i.0"
    if { ![ check_reduced_ $ind ] } {
      append lnstr "${i}\n"
    } else {
      incr last_line
    }
  }
}

proc get_last_line_num {} {
  set first_line [get_first_line_num]
  set last_line  [expr $first_line + [get_text_height] ]
  set j $first_line
  for {set i $first_line} { $i < $last_line } { incr i } {
    set ind "$j.0"
    puts $ind
    if { [ check_reduced_ $ind ] } {
      incr i -1
      incr j
    }
  }
  puts " >>> $j <<< "
  return j
}



wm title . "Editor"
menu .mbar
. config -menu .mbar

## The Main Buttons
.mbar add cascade -label "File" -underline 0 \
      -menu [menu .mbar.file -tearoff 0]

## File Menu ##
set m .mbar.file
$m add command -label "Open" -underline 0 -state disabled -command {  }
$m add separator
$m add command -label "Exit" -underline 1 -command exit

text .txt -width 40 -height 10 -wrap word -yscrollcommand ".scroll set" \
          -setgrid true -relief flat -bd 0 -maxundo 128 -undo true -font "Courier -12"
set lnstr "1\n2\n3\n4\n5\n6\n7\n8\n"
label .lln -width 5 -height 10 -justify right -bg white -textvariable lnstr \
           -font "Courier -12" -anchor ne -fg darkgray

scrollbar .scroll -command ".txt yview"
canvas .cnv -width 10 -height 10 -bg white

pack .scroll -side right -fill y
pack .lln -side left -fill y
pack .cnv -side left -fill y
pack .txt -expand yes -fill both

set lnum 0
foreach line $fcont {
  .txt insert end "$line\n"
  incr lnum
}
.txt edit reset

#proc show_txt {} {
#  global
#
#}

rename .txt .txt_
proc .txt {command args} {
  set result [uplevel .txt_ $command $args]

### Debug
  set debug 1
  if { $debug == 0 &&
       $command != "bbox" } {
    puts "$command $args"
  }
### End Debug1
  #puts [ .txt_ dump -mark 1.0 end ]
  #puts [ .txt_ dump -tag 1.0 end ]
  if { $command == "insert" ||
       $command == "delete" ||
       $command == "yview"  ||
       $command == "see"    || 
       $command == "edit" } {
    set ind [.txt_ index insert]
    if { [check_mtag $ind] || [check_mtag_ $ind] } {
      set n [get_mtag_n $ind ]
      .txt_ tag configure mtag${n}_ -elide 0
      .txt_ tag remove reduced mtag$n.first mtag$n.last
      .txt_ tag remove reduced_ mtag${n}_.first mtag${n}_.last
      .txt_ tag delete mtag${n} mtag${n}_
    }     
    update_tags
    redraw_cnv
    update_lln
  }
  return $result
}

bind .cnv <Expose> {update_tags;redraw_cnv;update_lln}

proc get_text_height {} {
  set fsize [ expr -( [lindex [ .txt_ cget -font ] 1 ] ) ]
  set hpix [ winfo height .txt ]
  set h [expr ( $hpix - 6) / ( $fsize + 1 ) ]
  return $h
}

proc get_first_line_num {} {
  #global first_line
  set ltotal [llength [split [.txt_ get 1.0 end] "\n" ] ]
  set first_line [expr int ( [ lindex [.txt_ yview] 0 ] * $ltotal + 1 ) ]
  return $first_line
}

proc update_tags {} {
  set lnum 1
  global mtagn
  set mflag 0
  foreach line [ split [.txt_ get 1.0 end] "\n" ] {
    if { [regexp {^\s*module(\s|$|\\)} $line] } {
      set fl 0
      set tags [.txt_ tag names $lnum.0]
      foreach t $tags {
        if { [regexp {mtag\d+} $t] } { set fl 1 }
      }
      if { $fl == 0 } {
        .txt_ tag add mtag$mtagn $lnum.0 $lnum.0+1l
        set mflag 1
      }
      incr lnum
      continue
    }
    if { $mflag == 1 } {
      .txt_ tag add mtag${mtagn}_ $lnum.0 $lnum.0+1l
    }
    if { [regexp {^\s*endmodule(\s|$|\\)} $line] && $mflag == 1 } {
      incr mtagn
      #puts ">> $mtagn"
      set mflag 0
    }
  incr lnum
  }
  #.txt_ tag bind mtag0 { puts "ZZZ" }
  #puts [.txt_ tag names]
  #.txt_ tag configure mtag0_ -elide 1
  
}

proc member { item list_ } {
  foreach zz $list_ {
    if { $item == $zz } {return 1}
  }
  return 0
}
#if { [ member "zzz" [list "zzz" "uu" "ccc"]] } { puts "Ok!" } else { puts "Nop..." }

proc member_re { item list_ } {
  foreach zz $list_ {
    if { [regexp $item $zz ] } {return 1}
  }
  return 0
}
#if { [ member_re "zzz" [list "zxzzzx" "uu" "ccc"]] } { puts "Ok!" } else { puts "Nop..." }


#puts [.txt_ index 3.0+1l-1c]

